// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module aes256_gcm_fsm 
(
  input logic clk,                 // system clock
  input logic reset_n,             // system reset
  input logic aes_busy,
  input logic aes_flush,
  input logic aes_start,
  input logic aes_last,
  input logic aes_data_in_valid,
  input logic aes_mask_seed_valid,
  input logic aes_key_in_valid,
  input logic aes_iv_in_valid,
  input logic aes_ctrl_reg_valid,
  input logic auth_tag_gen,
  input logic multH_generated,
  output logic aes_busy_out,
  output logic en_multH_gen,
  output logic aes_flush_done
);
 
 logic [1:0] aes_flush_cnt;

typedef enum logic [2:0] {
        IDLE, 
        START, 
        AES_DATA_OR_CTRL, 
        AES_DATA_IN, 
        GEN_AUTH_TAG, 
        AES_FLUSH,
        AES_FLUSH_CNT
        } state_t;
 
 state_t state; 
 logic aes_busy_fsm ;

 assign aes_busy_out = aes_busy_fsm || aes_busy;

 always_ff @(posedge clk or negedge reset_n)
 begin
   if (!reset_n) 
   begin
     state         <= IDLE;
     aes_busy_fsm  <= 1'b0;
     en_multH_gen  <= 1'b0;
     aes_flush_done  <= 1'b0;
     aes_flush_cnt <= 2'b00;
   end 
   else 
   begin
     case (state)
         IDLE : begin
           if (aes_start == 1'b1)
           begin
             state        <= START;
             aes_busy_fsm <= 1'b1;
             en_multH_gen <= 1'b1;
           end
           else
           begin
             state        <= IDLE;
             aes_busy_fsm <= 1'b0;
             en_multH_gen <= 1'b0;
           end
           aes_flush_cnt  <= 2'b00;
           aes_flush_done <= 1'b0;
         end
         START : begin
           aes_busy_fsm   <= 1'b1;
           aes_flush_cnt  <= 2'b00;
           aes_flush_done <= 1'b0;
           if (multH_generated == 1'b1)
           begin
             state        <= AES_DATA_OR_CTRL;
             en_multH_gen <= 1'b0;
           end
           else
           begin
             state        <= START;
             en_multH_gen <= 1'b1;
           end
         end
         AES_DATA_OR_CTRL : begin
           aes_busy_fsm   <= 1'b0;
           en_multH_gen   <= 1'b0;
           aes_flush_cnt  <= 2'b00;
           aes_flush_done <= 1'b0;
           if (aes_data_in_valid == 1'b1)
           begin
             state        <= AES_DATA_IN;
           end
           else
           begin
             state        <= AES_DATA_OR_CTRL;
           end
         end
         AES_DATA_IN : begin
           aes_busy_fsm   <= 1'b0;
           en_multH_gen   <= 1'b0;
           aes_flush_cnt  <= 2'b00;
           aes_flush_done <= 1'b0;
           if (aes_busy == 1'b0)
           begin
             if (aes_last == 1'b1)
             begin
               state        <= GEN_AUTH_TAG;
             end
             else 
             begin
               state        <= AES_DATA_OR_CTRL;
             end
           end
           else
           begin
             state        <= AES_DATA_IN;
           end
         end
         GEN_AUTH_TAG : begin //This state is not req but it is good to check if tag is generated.
           en_multH_gen   <= 1'b0;
           aes_flush_cnt  <= 2'b00;
           aes_flush_done <= 1'b0;
           aes_busy_fsm   <= 1'b1;
           if (auth_tag_gen == 1'b1)
           begin
             state        <= AES_FLUSH;
           end
           else
           begin
             state        <= GEN_AUTH_TAG;
           end
         end
         AES_FLUSH : begin
           en_multH_gen   <= 1'b0;
           aes_flush_cnt  <= 2'b00;
           aes_flush_done <= 1'b0;
           aes_busy_fsm   <= 1'b0;
           if (aes_flush == 1'b1)
           begin
             state        <= AES_FLUSH_CNT;
           end
           else
           begin
             state        <= AES_FLUSH;
           end
         end
         AES_FLUSH_CNT : begin
           aes_flush_cnt <= aes_flush_cnt + 1;
           //--reset Ctrl reg
           if (aes_flush_cnt == 2'b10)
           begin
             aes_flush_done <= 1'b1;
           end
           else
           begin
             aes_flush_done <= 1'b0;
           end
           //--state transition---
           if (aes_flush_cnt == 2'b11)
           begin
             state          <= IDLE;
             aes_busy_fsm   <= 1'b0;
           end
           else
           begin
             state          <= AES_FLUSH_CNT;
             aes_busy_fsm   <= 1'b1;
           end
         end
         default : begin
           state          <= IDLE;
           aes_busy_fsm   <= 1'b0;
           aes_flush_cnt  <= 2'b00;
           aes_flush_done <= 1'b0;
         end
     endcase

   end 
 end 

endmodule
